package com.culturalCenter.dataCenter.globalconfig.filter;


import com.culturalCenter.dataCenter.Utils.PathUtil;
import com.culturalCenter.dataCenter.customEntity.CustomRole;
import com.culturalCenter.dataCenter.entity.user.Rule;
import com.culturalCenter.dataCenter.mapper.user.RoleMapper;
import com.culturalCenter.dataCenter.mapper.user.RuleMapper;
import lombok.extern.slf4j.Slf4j;
import org.springframework.security.access.AccessDeniedException;
import org.springframework.security.access.ConfigAttribute;
import org.springframework.security.access.SecurityConfig;
import org.springframework.security.web.FilterInvocation;
import org.springframework.security.web.access.intercept.FilterInvocationSecurityMetadataSource;
import org.springframework.security.web.util.matcher.AntPathRequestMatcher;
import org.springframework.stereotype.Component;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.List;
import java.util.regex.Pattern;


/**
 * 从数据库读取url
 *
 * @author Rockylee
 */
@Component
@Slf4j
public class CustomFilterInvocationSecurityMetadataSource implements FilterInvocationSecurityMetadataSource {

    /**
     * 此map缓存 URL与其权限关系
     */
    public volatile HashMap<String, Collection<ConfigAttribute>> map = null;
    public volatile HashMap<String, String> mapRule = null;
    // @Autowired
    // PermissionMapper permissionMapper;
    @Resource
    private RoleMapper roleMapper;
    @Resource
    private RuleMapper ruleMapper;

    public void loadResourceDefine() {
        map = new HashMap<>();
        Collection<ConfigAttribute> array;
        ConfigAttribute cfg;
        List<CustomRole> urlList = roleMapper.findRoleUrl();
        for (CustomRole role : urlList) {
            if (role.getRoleUrl() == null || "".equals(role.getRoleUrl())) {
                continue;
            }
            array = new ArrayList<>();
            cfg = new SecurityConfig(role.roleCode);
            array.add(cfg);
            String roleUrl = "/**" + role.roleUrl;
            if (map.containsKey(roleUrl)) {
                map.get(roleUrl).add(cfg);
            } else {
                map.put(roleUrl, array);
            }
        }
    }

    public void loadRule() {
        mapRule = new HashMap<>();
        List<Rule> ruleList = (List<Rule>) ruleMapper.queryAll(new Rule());
        for (Rule role : ruleList) {
            String roleUrl = "/**" + role.getInterfaceUrl();
            mapRule.put(roleUrl, role.getInterfaceUrl());
        }
    }


    /**
     * 返回该url所需要的用户权限信息
     *
     * @param object: 储存请求url信息
     *
     * @return: null：标识不需要任何权限都可以访问
     */
    @Override
    public Collection<ConfigAttribute> getAttributes(Object object) throws IllegalArgumentException, AccessDeniedException {
        if (mapRule == null) {
            loadRule();
        }
        if (map == null) {
            loadResourceDefine();
        }

        HttpServletRequest request = ((FilterInvocation) object).getRequest();
        AntPathRequestMatcher matcher;
        // 如果在loadRule 中存在则进行权限认证
        if (isUrlMapRule(request)) {
            for (String url : map.keySet()) {
                // matcher = new AntPathRequestMatcher(url);
                if (Pattern.matches(PathUtil.getRegPath(url), request.getRequestURI())) {
                    return map.get(url);
                }
            }
            throw new AccessDeniedException("请联系管理员分配权限！");
        }
        return null;
        // 如果数据中没有找到相应url资源则为非法访问，要求用户登录再进行操作
        // return SecurityConfig.createList("找不到请求url");
    }

    private boolean isUrlMapRule(HttpServletRequest request) {
        for (String url : mapRule.keySet()) {
            if (Pattern.matches(PathUtil.getRegPath(url), request.getRequestURI())) {
                return true;
            }
        }
        return false;
    }

    @Override
    public Collection<ConfigAttribute> getAllConfigAttributes() {
        return null;
    }

    @Override
    public boolean supports(Class<?> aClass) {
        return FilterInvocation.class.isAssignableFrom(aClass);
    }

}
